﻿#region Copyright
//————————————————————————————————————————//
//	创建人员(Creator)    ：Huangyd
//	创建日期(Date)       ：2012-07-03
//  联系方式(Email)      ：aj-ayumi@163.com; gajayumi@gmail.com; ajayumi@me.com
//  描    述(Description)：
//
//	Copyright (C) 2012 ajayumi 版权所有
//————————————————————————————————————————//
#endregion
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Data;
using System.Security.Permissions;
using System.Web;
using System.Web.Configuration;
using System.Collections.Generic;
using System.Configuration.Provider;
using System.Data.Common;

namespace ajayumi.Platform.Web.SiteMapProvider
{
    /// <summary>
    /// SqlSiteMapProvider 类是从 StaticSiteMapProvider 类派生的，
    /// 它使用基本的 SQL 查询以及 DbCommand 和 DbDataReader 对象从 Microsoft SQL Server 数据库检索其信息。
    /// </summary>
    [AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
    public class SqlSiteMapProvider : StaticSiteMapProvider
    {
        private DbParameter m_DbParameter = null;
        private static readonly DbProviderFactory m_Factory = DbProviderFactories.GetFactory("System.Data.SqlClient");

        private string mConnStr = string.Empty;
        private int mIndexId, mIndexTitle, mIndexUrl, mIndexDesc, mIndexRoles, mIndexParent;
        private bool initialized = false;
        private Dictionary<string, SiteMapNode> mNodes = new Dictionary<string, SiteMapNode>();
        private SiteMapNode mRoot;

        public bool IsInitialized { get { return this.initialized; } }

        /// <summary>
        /// 初始化提供程序
        /// </summary>
        /// <param name="name">提供程序的名称</param>
        /// <param name="config">配置参数</param>
        public override void Initialize(string name, NameValueCollection config)
        {
            if (!this.IsInitialized)
            {
                if (null == config)
                {
                    throw new ArgumentNullException("config");
                }
                if (string.IsNullOrEmpty(name))
                {
                    name = "SqlSiteMapProvider";
                }
                if (string.IsNullOrEmpty(config["description"]))
                {
                    config.Remove("description");
                    config.Add("description", "SQL site map provider");
                }
                base.Initialize(name, config);

                string connStrName = config["connectionStringName"];
                if (string.IsNullOrEmpty(connStrName))
                {
                    throw new ProviderException("连接字符串无效");
                }
                config.Remove("connectionStringName");
                if (null == WebConfigurationManager.ConnectionStrings[connStrName])
                {
                    throw new ProviderException("数据库连接字符串为空");
                }
                mConnStr = WebConfigurationManager.ConnectionStrings[connStrName].ConnectionString;
                if (string.IsNullOrEmpty(mConnStr))
                {
                    throw new ProviderException("数据库连接字符串无效");
                }
                if (null != config["securityTrimmingEnabled"])
                {
                    config.Remove("securityTrimmingEnabled");
                }
                if (config.Count > 0)
                {
                    string attr = config.GetKey(0);
                    if (!string.IsNullOrEmpty(attr))
                    {
                        throw new ProviderException("不能够识别的属性：" + attr);
                    }
                }
                this.initialized = true;
            }
        }

        /// <summary>
        /// 从数据库中检索站点数据并构建站点地图
        /// </summary>
        /// <returns></returns>
        public override SiteMapNode BuildSiteMap()
        {
            //因为SiteMap类时静态的
            //所以应该确保站点地图被构建完成之前，它不要被修改
            lock (this)
            {
                //如果提供程序没有被初始化，抛出异常
                if (!this.IsInitialized)
                {
                    throw new Exception("BuildSiteMap不正确，提供程序没有被初始化");
                }
                if (null == mRoot)
                {
                    //清空节点
                    this.Clear();
                    using (DbConnection conn = m_Factory.CreateConnection())
                    {
                        conn.ConnectionString = this.mConnStr;
                        using (DbCommand cmd = m_Factory.CreateCommand())
                        {
                            cmd.CommandText = "SELECT * FROM SiteMap ORDER BY ID";
                            cmd.Connection = conn;
                            conn.Open();

                            using (DbDataReader dr = cmd.ExecuteReader())
                            {
                                this.mIndexId = dr.GetOrdinal("ID");
                                this.mIndexUrl = dr.GetOrdinal("Url");
                                this.mIndexTitle = dr.GetOrdinal("Title");
                                this.mIndexDesc = dr.GetOrdinal("Description");
                                this.mIndexRoles = dr.GetOrdinal("Roles");
                                this.mIndexParent = dr.GetOrdinal("ParentID");
                                if (dr.Read())
                                {
                                    this.mRoot = CreateSiteMapNodeFromDataReader(dr);
                                    this.AddNode(this.mRoot, null);
                                    while (dr.Read())
                                    {
                                        SiteMapNode node = CreateSiteMapNodeFromDataReader(dr);
                                        GetParentNodeFromDataReader(dr);
                                    }
                                }
                            }
                        }
                    }
                }
                return this.mRoot;
            }
        }

        /// <summary>
        /// 获得已经构建完成的根节点
        /// </summary>
        /// <returns></returns>
        protected override SiteMapNode GetRootNodeCore()
        {
            BuildSiteMap();
            return this.mRoot;
        }



        private SiteMapNode CreateSiteMapNodeFromDataReader(DbDataReader dr)
        {
            if (dr.IsDBNull(this.mIndexId))
            {
                throw new ProviderException("空节点ID");
            }
            string id = dr.GetString(this.mIndexId);
            if (this.mNodes.ContainsKey(id))
            {
                throw new ProviderException("重复的节点ID");
            }
            string title = dr.IsDBNull(this.mIndexTitle) ? null : dr.GetString(this.mIndexTitle).Trim();
            string url = dr.IsDBNull(this.mIndexUrl) ? null : dr.GetString(this.mIndexUrl).Trim();
            string description = dr.IsDBNull(this.mIndexDesc) ? null : dr.GetString(this.mIndexDesc).Trim();
            string roles = dr.IsDBNull(this.mIndexRoles) ? null : dr.GetString(this.mIndexRoles).Trim();
            string[] roleList = null;
            if (string.IsNullOrEmpty(roles))
            {
                roleList = new string[] { "*" };
            }
            else
            {
                roleList = roles.Split(new char[] { ',', ';' }, 512);
            }
            SiteMapNode node = new SiteMapNode(this, id.ToString(), url, title, description, roleList, null, null, null);
            mNodes.Add(id, node);
            return node;
        }

        private SiteMapNode GetParentNodeFromDataReader(DbDataReader dr)
        {
            if (dr.IsDBNull(this.mIndexParent))
            {
                throw new ProviderException("空的父ID");
            }
            string pid = dr.GetString(this.mIndexParent);
            if (!mNodes.ContainsKey(pid))
            {
                throw new ProviderException("无效的父ID");
            }
            return this.mNodes[pid];
        }

        /// <summary>
        /// 清除站点地图中的节点
        /// </summary>
        protected override void Clear()
        {
            lock (this)
            {
                this.mRoot = null;
                base.Clear();
            }
        }

        /// <summary>
        /// 获取SiteMap根节点
        /// </summary>
        public override SiteMapNode RootNode
        {
            get
            {
                return this.BuildSiteMap();
            }
        }

    }
}
